﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using SharedGenomics.Annotations;
using SharedGenomics.Workbench.Annotations;

namespace SharedGenomics.Workbench.Tests.Annotations
{
    [TestClass]
    public class AnnotationInfoSetTests
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorShouldThrowIfAnnotationValueNull()
        {
            AnnotationInfoSet set = new AnnotationInfoSet(null, new[] { AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.GoogleSearch) });
        }

        [TestMethod]
        public void ConstructorShouldInitialiseCount()
        {
            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, new[] { AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.GoogleSearch) });

            Assert.AreEqual(1, set.Count);
            Assert.AreEqual(0, set.FinishedCount);
        }

        [TestMethod]
        public void ConstructorShouldAllowNullDescriptorCollection()
        {
            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, null);

            Assert.AreEqual(0, set.Count);
        }

        [TestMethod]
        public void ConstructorShouldIngoreNullDescriptors()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.GoogleSearch),
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.NcbiSummary),
                null
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            Assert.AreEqual(2, set.Count);
        }

        [TestMethod]
        public void ShouldUpdateFinishedCount()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.GoogleSearch),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            set.AddAnnotation(new GoogleSearchAnnotation("rs001"));
            Assert.AreEqual(1, set.FinishedCount);
        }

        [TestMethod]
        public void ShouldNotUpdateFinishedCount()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.NcbiSummary),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            //set should ignore any completed annotation that does not correspond to any request
            set.AddAnnotation(new GoogleSearchAnnotation("rs001"));

            Assert.AreEqual(0, set.FinishedCount);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowIfAnnotationNull()
        {
            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, null);

            set.AddAnnotation(null);
        }

        [TestMethod]
        public void ShouldUpdateFailedCount()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.GoogleSearch),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            set.AnnotationFailed(AnnotationKey.GoogleSearch);

            Assert.AreEqual(1, set.FailedCount);
        }

        [TestMethod]
        public void ShouldNotUpdatedFailedCount()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.NcbiSummary),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            set.AnnotationFailed(AnnotationKey.GoogleSearch);

            Assert.AreEqual(0, set.FailedCount);
        }

        [TestMethod]
        public void ShouldNotUpdateFailedCountIfTypeNull()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.NcbiSummary),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            set.AnnotationFailed(null);

            Assert.AreEqual(0, set.FailedCount);
        }

        [TestMethod]
        public void ShouldGetInfoForKey()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                AnnotationDescriptor.GetDescriptorForKey(AnnotationKey.NcbiSummary),
            };

            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, descriptors);

            Assert.IsNotNull(set[AnnotationKey.NcbiSummary]);
        }

        [TestMethod]
        public void ShouldReturnNullInfoIfKeyNotFound()
        {
            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, new List<AnnotationDescriptor>());

            Assert.IsNull(set[AnnotationKey.GoogleSearch]);
        }

        [TestMethod]
        public void ShouldReturnNullIfKeyNull()
        {
            AnnotationValue value = new AnnotationValue(AnnotationKey.SnpName, "rs001");
            AnnotationInfoSet set = new AnnotationInfoSet(value, new List<AnnotationDescriptor>());

            Assert.IsNull(set[null]);
        }
    }
}
